#!/usr/bin/python -S
"""
regex_test.py: Test for public API of Annex CREs.
"""

import unittest

import annex
from annex import re_compat


class RegexTest(unittest.TestCase):

  def _testDigit(self, r):
    """Helper function."""
    # match() -- unanchored
    m = r.match('123abc')
    self.assertEqual('123', m)
    m = r.match('abc123')
    self.assertEqual('123', m)

    # match(search=False)
    m = r.match('123abc', search=False)
    self.assertEqual('123', m)
    m = r.match('abc123', search=False)
    self.assertEqual(None, m)

    # matchspan
    span = r.matchspan('123')
    self.assertEqual('123', span.value)
    span = r.matchspan('123abc')
    self.assertEqual('123', span.value)

  def testRegex(self):
    # You can use a grammar or just an expression.
    r = annex.Regex('Start = digit+')
    self._testDigit(r)

    r = annex.Regex('digit+')
    self._testDigit(r)

    # Add a degenerate rule.
    r = annex.Regex('Start = d+   d = digit ')
    self._testDigit(r)

  def testRegexMethods(self):
    r = annex.Regex('{digit+}')

    t = r.split('3 days in 30 months')
    self.assertEqual('3', t[1])

    a = r.iterate('3 days in 30 months')
    self.assertEqual(['3', '30'], list(a))

  def testNewApi(self):
    print

    r = annex.Regex('digit+')
    print r.capture('3')
    print r.capture('a3b')
    print r.capture('a3b', search=False)  # don't search past 'a'
    print r.capture('blah')

    print r.capturespans('3')
    c = r.capturespans('a3b')
    print c, c['MATCH'].value, c['MATCH'].start, c['MATCH'].end
    print r.capturespans('blah')

    print r.match('a3b'), '!!'
    print r.match('blah')
    print r.matchspan('a3b')

    r = annex.Regex('{digit+}')
    print r.capture('3')
    print r.capture('a3b')
    c = r.capturespans('a3b')
    print c, c[1].value, c[1].start, c[1].end

    print r.match('a3b')

    r = annex.Regex('{digit+ as year}')
    print r.capture('3')
    print r.capture('a3b')

    c = r.capturespans('a3b')
    print c, c['year'].value, c['year'].start, c['year'].end

    print r.match('a3b')

    r = annex.Regex('{digit+ as year} "/" {digit+ as month}')
    print r.capture('2012/10/1')
    print r.match('2012/10/1')

  def testIterate(self):
    print
    d = annex.Regex(r'{digit+ as id}')
    print list(d.iterate('abc 123 def 45.'))
    print list(d.iterate('abc 123 def 45.', span=True))

    print list(d.iterate('abc 123 def 45.', capture=True))
    print list(d.iterate('abc 123 def 45.', capture=True, span=True))


  def testCompat(self):
    r = re_compat.compile('{digit+}')
    # TODO: Should re_compat change the meaning of match()?
    #m = r.match_('321here')
    #self.assertEqual('321', m.group(0))

    s = r.sub(r'[\1]', '3 days in 30 months')
    self.assertEqual('[3] days in [30] months', s)

    s, n = r.subn(r'[\1]', '3 days in 30 months')
    self.assertEqual(2, n)

    r = annex.Regex('{digit+}')
    # TODO: fix this exception.
    from annex import cre_compile
    #self.assertRaises(cre_compile.Error, r.match_, '321here')
    self.assertRaises(cre_compile.Error, r.sub, '', '')
    self.assertRaises(cre_compile.Error, r.subn, '', '')

  def testReplace(self):
    r = annex.Regex('{digit+}')

    # Legacy syntax
    s = r.replace('3 days in 30 months', repl=r'[\1]')
    self.assertEqual('[3] days in [30] months', s)

    # replacen
    s, n = r.replacen('3 days in 30 months', repl=r'[\1]')
    self.assertEqual(2, n)

    # function
    def replace_func(match):
      return '[' + match.group(1) + ']'
    s = r.replace('3 days in 30 months', func=replace_func)
    self.assertEqual('[3] days in [30] months', s)

  def testReplaceWithFormat(self):
    r = annex.Regex("'$' {digit+ as num}")

    s = r.replace('$1 $2', format='[{0}]')
    self.assertEqual('[$1] [$2]', s)

    s = r.replace('$1 $2', format='[{1}]')
    self.assertEqual('[1] [2]', s)

    s = r.replace('$1 $2', format='[{num}]')
    self.assertEqual('[1] [2]', s)

  def testReplaceWithTemplate(self):
    r = annex.Regex("'$' {digit+ as num}")

    s = r.replace('$1 $2', template='[$0]')
    self.assertEqual('[$1] [$2]', s)

    s = r.replace('$1 $2', template='[$1]')
    self.assertEqual('[1] [2]', s)

    s = r.replace('$1 $2', template='[$num]')
    self.assertEqual('[1] [2]', s)

    # ${}
    s = r.replace('$1 $2', template='${num}abc')
    self.assertEqual('1abc 2abc', s)

  def testFreeFunctions(self):
    # Test non-compiling versions.
    pass

  # TODO: Test there errors.
  def testLexErrors(self):
    pass

  def testParseErrors(self):
    pass

  def testConvertTo(self):
    # Shortcut to convert to an ERE for grep.  You could also instantiate the
    # regex object, and then run r.toposix()

    # Should 'start' be the start symbol?  Or allow no symbols.

    s = annex.to_ere('Start = &space+')
    print s

  def ConvertFrom(self):
    # later
    # annex.from_python -> Regex object
    # annex.from_posix ->  Regex object
    #
    # these of course should use the lexer and parser abstractions.
    pass


if __name__ == '__main__':
  unittest.main()
